package com.cskaoyan.wordmemorize.service.impl.app;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.annotation.OperateLog;
import com.cskaoyan.wordmemorize.common.exception.BusinessException;
import com.cskaoyan.wordmemorize.converter.UserPrivilegeConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.admin.UserVocAISituationDTO;
import com.cskaoyan.wordmemorize.dto.app.*;
import com.cskaoyan.wordmemorize.request.AIReviewReadCommand;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserFavoriteCommand;
import com.cskaoyan.wordmemorize.request.UserVocExampleSentenceCommand;
import com.cskaoyan.wordmemorize.service.UserPrivilegeService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.cskaoyan.wordmemorize.common.constant.UserVocBoundEnum.USER_VOC_BOUND_LOG_TYPE_CONSUME;

@Service
public class UserPrivilegeServiceImpl implements UserPrivilegeService {


    private final ChatClient chatClient;

    public UserPrivilegeServiceImpl(ChatClient.Builder builder) {

        this.chatClient = builder.build();
    }

    @Autowired
    UserPrivilegeConverter userPrivilegeConverter;


    @Autowired
    UserNotRememberMapper userNotRememberMapper;
    @Autowired
    UserVocRevMapper userVocRevMapper;
    @Autowired
    private VocChapBookMapper vocChapBookMapper;
    @Autowired
    private UserVocAISituationOptionMapper userVocAISituationOptionMapper;

    // 1.APP端表示不想背
    @Override
    @Transactional
    public void notRemember(Long vocId, Long userId) {
        // TODO
        // 在user_not_remember表中添加的数据
        UserNotRememberDO userNotRememberDO = new UserNotRememberDO();
        userNotRememberDO.setUserId(userId);
        userNotRememberDO.setVocId(vocId);
        boolean ret1 = userNotRememberMapper.insertOrUpdate(userNotRememberDO);
        // 如果user_voc_rev表中有这个数据，则删除
        QueryWrapper<UserVocRevDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("voc_id", vocId)
                .eq("user_id", userId);
        if (userVocRevMapper.exists(queryWrapper)) {
            userVocRevMapper.delete(queryWrapper);
        }
    }

    // 2.APP端取消标识不想背
    @Override
    @Transactional
    public void cancelNotRemember(Long vocId, Long userId) {
        // TODO
        // 在user_not_remember表中的数据is_delete设置为1
        UpdateWrapper<UserNotRememberDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userId)
                .eq("voc_id", vocId);
        int ret = userNotRememberMapper.delete(updateWrapper);
        if (ret == 0) {
            throw new BusinessException("请求失败", 500);
        }

    }


    @Autowired
    UserVocExampleSentenceMapper userVocExampleSentenceMapper;

    // 3.APP端添加用户自建例句
    @Override
    @Transactional
    public UserExampleSentenceDTO addUserVocSentence(UserVocExampleSentenceCommand command, Long userId) {
        // Command-> DO
        // user_voc_sentence表中添加数据
        UserVocExampleSentenceDO userVocExampleSentenceDO
                = userPrivilegeConverter.userVocExampleSentenceCommand2DO(command);
        int i = userVocExampleSentenceMapper.insert(userVocExampleSentenceDO);
        if (i == 0) {
            throw new BusinessException("请求失败", 500);
        }
        // DO -> DTO
        UserExampleSentenceDTO userExampleSentenceDTO
                = userPrivilegeConverter.userVocExampleSentenceDO2DTO(userVocExampleSentenceDO);
        return userExampleSentenceDTO;
    }

    // 4.APP端获取用户自建例句
    @Override
    @Transactional
    public PageDTO<DisplayUserVocSentenceDTO> getUserVocSentence(PageRequest pageRequest, Long userId) {
        // 分页查询
        Page page = new Page(pageRequest.getPageNum(), pageRequest.getCount());
        QueryWrapper<UserVocExampleSentenceDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        userVocExampleSentenceMapper.selectPage(page, queryWrapper);
        // 获取分页中的每一条记录
        List<UserVocExampleSentenceDO> userVocExampleSentenceDOList = page.getRecords();

        // 总记录数
        Long total = page.getTotal();

        // 将userVocExampleSentenceDOList按照vocId分组
        Map<Long, List<UserVocExampleSentenceDO>> sentencesOfVoc
                = userVocExampleSentenceDOList.stream().collect(Collectors.groupingBy(UserVocExampleSentenceDO::getVocId));


        List<DisplayUserVocSentenceDTO> displayUserVocSentenceDTOS = sentencesOfVoc.entrySet().stream().map(entry -> {
            Long vocId = entry.getKey();
            List<UserVocExampleSentenceDO> sentences = entry.getValue();
            String vocContent = sentences.get(0).getVocContent();

            DisplayUserVocSentenceDTO displayUserVocSentenceDTO = new DisplayUserVocSentenceDTO();
            displayUserVocSentenceDTO.setUserId(userId.toString());
            displayUserVocSentenceDTO.setVocId(vocId.toString());
            displayUserVocSentenceDTO.setVocContent(vocContent);
            List<UserVocSentenceDTO> userVocSentenceDTOS = userPrivilegeConverter.userVocSentenceDOs2DTOs(sentences);
            displayUserVocSentenceDTO.setSentences(userVocSentenceDTOS);
            return displayUserVocSentenceDTO;
        }).collect(Collectors.toList());

        // 封装成PageDTO
        PageDTO<DisplayUserVocSentenceDTO> pageDTO
                = userPrivilegeConverter.displayUserVocSentenceDTOList2PageDTO(displayUserVocSentenceDTOS, total);

        return pageDTO;
    }

    // 5.APP端更新用户自建例句
    @Override
    public void updateUserVocSentence(UserVocExampleSentenceCommand command, Long userId) {
        // Command->DO
        UserVocExampleSentenceDO userVocExampleSentenceDO
                = userPrivilegeConverter.userVocExampleSentenceCommand2DO(command);
        // 更新数据库
        UpdateWrapper<UserVocExampleSentenceDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userId);
        userVocExampleSentenceMapper.update(userVocExampleSentenceDO, updateWrapper);

    }

    // 6.APP端删除用户自建例句

    @Override
    public void deleteUserVocSentence(Long id) {
        // 删除数据库
        int i = userVocExampleSentenceMapper.deleteById(id);

    }


    @Autowired
    UserFavoriteMapper userFavoriteMapper;

    // 7.APP端单个添加收藏单词
    // 单词收藏涉及的表有:
    // user_favorite，
    // voc_meaning(因为在收藏列表中还会显示单词释义)，
    // user_voc_rev(还可以显示该单词是否已选择复习)
    // 问题: selected = 1 表示选中,是否要同步修改user_voc_rev表中的selected字段?
    @Override
    public void addFavorite(UserFavoriteCommand userFavoriteCommand, Long userId) {
        // Command->DO
        UserFavoriteDO userFavoriteDO
                = userPrivilegeConverter.userFavoriteCommand2DO(userFavoriteCommand);
        // 插入数据库
        userFavoriteMapper.insertOrUpdate(userFavoriteDO);

    }

    // 8.APP端取消收藏单词
    @Override
    public void cancelFavorite(List<Long> ids, Long userId) {
        // 删除数据库
        QueryWrapper<UserFavoriteDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId)
                .in("id", ids);
        userFavoriteMapper.delete(queryWrapper);

    }

    // 9.APP端批量添加收藏单词
    @Override
    public void addFavoriteBulk(List<UserFavoriteCommand> userFavoriteCommand, Long userId) {
        // Command->DO
        List<UserFavoriteDO> userFavoriteDOs
                = userPrivilegeConverter.userFavoriteDOs2DTOs(userFavoriteCommand);
        // 插入数据库
        for (UserFavoriteDO userFavoriteDO : userFavoriteDOs) {
            userFavoriteDO.setUserId(userId);
            userFavoriteMapper.insertOrUpdate(userFavoriteDO);
        }

    }

    // 10.APP端获取单词收藏列表
    @Autowired
    VocMeaningMapper vocMeaningMapper;

    @Override
    @Transactional
    public PageDTO<UserFavoriteDTO> getUserFavoriteList(PageRequest pageRequest, Long userId) {
        // 分页查询
        Page page = new Page(pageRequest.getPageNum(), pageRequest.getCount());
        QueryWrapper<UserFavoriteDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        userFavoriteMapper.selectPage(page, queryWrapper);

        // 1.获取分页中的每一条记录,interpretations字段为空
        List<UserFavoriteDO> userFavoriteDOList = page.getRecords();
        // 总记录数,等于单词的总数
        Long total = page.getTotal();

        // 2.interpretations字段需要查询voc_meaning表
        for (UserFavoriteDO userFavoriteDO : userFavoriteDOList) {
            Long vocId = userFavoriteDO.getVocId();
            QueryWrapper<VocMeaningDO> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("voc_id", vocId);
            List<VocMeaningDO> vocMeaningDOList = vocMeaningMapper.selectList(queryWrapper1);
            userFavoriteDO.setInterpretations(vocMeaningDOList);
        }

        // 3.查询user_voc_rev表,判断单词是否已选择复习
        for (UserFavoriteDO userFavoriteDO : userFavoriteDOList) {
            Long vocId = userFavoriteDO.getVocId();
            QueryWrapper<UserVocRevDO> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("voc_id", vocId)
                    .eq("user_id", userId);
            // 如果user_voc_rev表中有该单词,则selected字段为1
            if (userVocRevMapper.exists(queryWrapper1)) {
                userFavoriteDO.setSelected(1);
            } else {
                userFavoriteDO.setSelected(0);
            }
        }

        // DO->DTO
        PageDTO<UserFavoriteDTO> userFavoriteDTOList
                = userPrivilegeConverter.userFavoriteDOPage2PageDTO(userFavoriteDOList, total);

        return userFavoriteDTOList;
    }


    // 11.APP端获取词书进度***
    @Autowired
    VocBookMapper vocBookMapper;

    @Override
    public UserVocBookStatisticsDTO getSelectedBookStatistics(Long userId, Long bookId) {
        // 在表voc_book中查询
        VocBookDO vocBookDO = vocBookMapper.selectById(bookId);
        // 1.词书单词总数
        Integer vocCount = vocBookDO.getVocCount();

        // 在表user_voc_rev中查询的所有单词
        QueryWrapper<UserVocRevDO> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("user_id", userId);
        List<UserVocRevDO> vocRevDOList = userVocRevMapper.selectList(queryWrapper1);

        // 该书已选的单词列表
        List<UserVocRevDO> selectedVocFromThisBookList = new ArrayList<>();
        Integer selectedCountFromThisBook = vocRevDOList.size();
        for (UserVocRevDO userVocRevDO : vocRevDOList) {
            Long vocId = userVocRevDO.getVocId();
            QueryWrapper<VocChapBookDO> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.eq("voc_id", vocId);
            if (!vocChapBookMapper.exists(queryWrapper2)) {
                selectedVocFromThisBookList.add(userVocRevDO);
            }
        }
        // 2.未选单词数量
        Integer unSelectedCount = vocCount - selectedCountFromThisBook;
        // 3.熟悉的单词数量: 单词的复习间隔>= 365的单词
        Integer familiarCount = 0;
        // 4.不熟悉的单词指: 还处于学习状态(复习时间 = 今天)的单词
        Integer unFamiliarCount = 0;
        // 5.一般的单词:  已处于复习状态(复习时间 != 今天)，且复习时间间隔 < 365的单词
        Integer generalCount = 0;
        // 6.已选未学的单词数量(复习次数 = 0)
        Integer notStartedCount = 0;
        for (UserVocRevDO selectedVocFromThisBook : selectedVocFromThisBookList) {
            // 当前时间
            LocalDate now = LocalDate.now();
            if (selectedVocFromThisBook.getReviewInterval() != null && selectedVocFromThisBook.getNextReviewDate() == now) {
                // 如果单词的复习时间 = 今天,则不熟悉的单词数量+1
                unFamiliarCount++;
            } else if (selectedVocFromThisBook.getNextReviewDate() != null && selectedVocFromThisBook.getReviewInterval() >= 365) {
                // 如果单词的复习时间间隔 >= 365,则熟悉的单词数量+1
                familiarCount++;
            } else if (selectedVocFromThisBook.getNextReviewDate() != null && selectedVocFromThisBook.getNextReviewDate() != now && selectedVocFromThisBook.getReviewInterval() < 365) {
                // 如果单词的复习时间!= 今天,且复习时间间隔 < 365,则一般的单词数量+1
                generalCount++;
            } else if (selectedVocFromThisBook.getNextReviewDate() != null && selectedVocFromThisBook.getTotalReview() == 0 || selectedVocFromThisBook.getType() == 0) {
                // 如果单词的复习次数 = 0,则已选未学的单词数量+1
                notStartedCount++;
            }
        }
        // 封装成UserVocBookStatisticsDTO
        UserVocBookStatisticsDTO userVocBookStatisticsDTO = new UserVocBookStatisticsDTO();
        userVocBookStatisticsDTO.setUnFamiliar(unFamiliarCount);
        userVocBookStatisticsDTO.setGeneral(generalCount);
        userVocBookStatisticsDTO.setFamiliar(familiarCount);
        userVocBookStatisticsDTO.setNotStarted(notStartedCount);
        userVocBookStatisticsDTO.setTotal(vocCount);
        userVocBookStatisticsDTO.setUnSelected(unSelectedCount);
        return userVocBookStatisticsDTO;
    }

    // 12.APP端获取AI阅读模式风格以及选项**
    @Autowired
    UserVocAISituationMapper userVocAISituationMapper;
    @Autowired
    UserVocAISituationOptionMapper userVocAISituationOptionMapperMapper;

    @Override
    public List<UserVocAISituationDTO> getAIReviewReadOptions() {
        // 查询user_voc_ai_situation表,获取所有的AI阅读模式
        List<UserVocAISituationDO> userVocAISituationDOList = userVocAISituationMapper.selectList(null);
        for (UserVocAISituationDO userVocAISituationDO : userVocAISituationDOList) {
            Long id = userVocAISituationDO.getId();
            // 查询user_voc_ai_situation_option表,获取所有的选项
            QueryWrapper<UserVocAISituationOptionDO> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("situation_id", id);
            List<UserVocAISituationOptionDO> userVocAISituationOptionDOList = userVocAISituationOptionMapperMapper.selectList(queryWrapper);
            // 将userVocAISituationOptionDOList赋值到UserVocAISituationDO
            userVocAISituationDO.setOptions(userVocAISituationOptionDOList);
        }
        // DO->DTO
        List<UserVocAISituationDTO> userVocAISituationDTOList = userPrivilegeConverter.userVocAISituationDOs2DTOs(userVocAISituationDOList);
        return userVocAISituationDTOList;
    }

    // 13.APP端获取用户剩余免费AI阅读次数***
    @Autowired
    LevelPrivilegeMapper levelPrivilegeMapper;
    @Autowired
    UserPrivilegeHistoryMapper userPrivilegeHistoryMapper;

    @Override
    public Integer getUserVocAIReadRemainFreeCount(Long userId) {
        // 先去level_privilege表中查询用户的权限码privilege_code = review:ai:read
        // 以及用户的权限码对应的免费次数free_count
        QueryWrapper<LevelPrivilegeDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("privilege_code", "review:ai:read");
        LevelPrivilegeDO levelPrivilegeDO = levelPrivilegeMapper.selectOne(queryWrapper);
        Integer freeCount = levelPrivilegeDO.getFreeCount();


        // 在user_privilege_use_statistics表中查询用户(userId)的权限码(review:ai:read)使用次数
        // 查询用户的权限码使用次数 user_count字段
        QueryWrapper<UserPrivilegeUseStatisticsDO> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("user_id", userId)
                .eq("privilege_code", "review:ai:read");
        Integer useCount = userPrivilegeHistoryMapper.selectOne(queryWrapper1).getUseCount();

        // 剩余免费次数 = 免费次数 - 使用次数
        Integer remainFreeCount = freeCount - useCount;
        return remainFreeCount >= 0 ? remainFreeCount : 0;
    }

    // 14.APP端获取AI阅读结果****

    @Value("classpath:/prompt/ai-read-system-message.st")
    private Resource systemResource;
    @Value("classpath:/prompt/ai-read-user-message.st")
    private Resource userResource;

    @Autowired
    UserVocBoundStatisticsMapper userVocBoundStatisticsMapper;
    @Autowired
    UserVocBoundLogMapper userVocBoundLogMapper;

    @Override
    @Transactional
    public List<AIReviewReadDTO> getAIReviewReadContent(AIReviewReadCommand command, Long userId) {
        // 1. 获取用户剩余免费AI阅读次数
        // 然后判断是使用次数还是单词上限
        getFreeCount(userId);

        // 直接利用模版文件内容创建PromptTemplate对象
        SystemPromptTemplate systemPromptTemplate
                = new SystemPromptTemplate(systemResource);
        PromptTemplate userTemplate = new PromptTemplate(userResource);
        HashMap<String, Object> model = new HashMap<>();
        model.put("situation", command.getSituationName());
        model.put("option", command.getOptionName());
        model.put("words", command.getVocList());

        String type;
        if ("教育模式".equals(command.getSituationName()))
            model.put("type", "短文");
        else if ("对话模式".equals(command.getSituationName()))
            model.put("type", "对话");
        else if ("故事模式".equals(command.getSituationName()))
            model.put("type", "故事");


        Message userMessage = userTemplate.createMessage(model);
        Message systemMessage = systemPromptTemplate.createMessage();


        List<AIReviewReadDTO> entity = chatClient.prompt(new Prompt(List.of(systemMessage, userMessage)))
                .call()
                .entity(new ParameterizedTypeReference<List<AIReviewReadDTO>>() {
                });


        return entity;
    }

    private void getFreeCount(Long userId) {
        // 先判断用户是否有免费次数
        Integer remainFreeCount = getUserVocAIReadRemainFreeCount(userId);

        // 封装user_voc_bound_log表中的数据
        UserVocBoundLogDO userVocBoundLogDO = new UserVocBoundLogDO();
        userVocBoundLogDO.setDescription("使用AI阅读");
        userVocBoundLogDO.setType(USER_VOC_BOUND_LOG_TYPE_CONSUME.getValue());
        userVocBoundLogDO.setUserId(userId);

        //
        QueryWrapper<LevelPrivilegeDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("privilege_code", "review:ai:read");
        LevelPrivilegeDO levelPrivilegeDO = levelPrivilegeMapper.selectOne(queryWrapper);
        // 每次AI阅读消耗的单词数
        Integer requireVocBound = levelPrivilegeDO.getRequireVocBound();

        if (remainFreeCount > 0) {
            // 如果有免费次数,则每次调用都要在user_privilege_use_statistics表中use_count字段+1
            UpdateWrapper<UserPrivilegeUseStatisticsDO> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("user_id", userId)
                    .eq("privilege_code", "review:ai:read")
                    .setSql("use_count = use_count + 1");
            userPrivilegeHistoryMapper.update(updateWrapper);

            // 在user_voc_bound_log表中添加一条记录(type,count,description,user_id)
            userVocBoundLogDO.setCount(0);
            userVocBoundLogMapper.insert(userVocBoundLogDO);
        } else {
            // 如果没有免费次数,则每次调用都要扣减20个单词上限
            // (修改user_voc_bound_statistics表的occupied字段+10和available字段-10)
            UpdateWrapper<UserVocBoundStatisticsDO> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("user_id", userId)
                    .setSql("occupied = occupied + " + requireVocBound)
                    .setSql("available = available - " + requireVocBound);
            userVocBoundStatisticsMapper.update(updateWrapper);

            // 如果可用单词available字段<0,则抛出异常
            if (userVocBoundStatisticsMapper.selectOne(updateWrapper).getAvailable() < 0) {
                throw new BusinessException("可用单词不足" + requireVocBound, 500);
            }

            // 在user_voc_bound_log表中添加一条记录(type,count,description,user_id)
            userVocBoundLogDO.setCount(20);
            userVocBoundLogMapper.insert(userVocBoundLogDO);
        }
    }

}
